/*
MIT License 

Copyright (c) 2021 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов, 

https://bmstu.codes/lsx/simodo/loom
*/

#ifndef simodo_interpret_host_fuze_ParsingTableBuilder_SLR
#define simodo_interpret_host_fuze_ParsingTableBuilder_SLR

/*! \file ParsingTableBuilder_SLR.h
    \brief Формирование таблицы разбора методом SLR
*/

#include "simodo/interpret/builtins/hosts/fuze/ParsingTableBuilder_abstract.h"

#include <unordered_map>

namespace simodo::interpret::builtins
{
    /*!
     * \brief Класс формирование таблицы разбора по заданным правилам грамматики методом SLR(0)
     */
    class ParsingTableBuilder_SLR : public ParsingTableBuilder_abstract
    {
        std::unordered_map<std::u16string,std::vector<inout::Lexeme>> _reduce_symbol_set;
                                                            ///< Ассоциативный массив с привязкой продукций
                                                            ///< к возможным для них лексемам языка (нужен для ускорения работы)
    public:
        ParsingTableBuilder_SLR() = delete;    ///< Пустой конструктор не поддерживается!

        /*!
         * \brief Конструктор построителя таблицы разбора методом SLR
         * \param m             Интерфейсная ссылка на объект обеспечения вывода информации в вызываемую программу
         * \param grammar_name  Наименование грамматики, которую нужно загрузить
         * \param g             Структура грамматики
         * \param strict_rule_consistency Признак строгости в проверках согласованности таблицы разбора
         */
        ParsingTableBuilder_SLR(const inout::uri_set_t & files,
                                inout::Reporter_abstract & m,
                                const std::string & grammar_name,
                                parser::Grammar & g,
                                bool strict_rule_consistency=true)
            : ParsingTableBuilder_abstract(files, m, grammar_name, g, strict_rule_consistency)
        {}

    protected:
        /*!
         * \brief Метод построения таблицы состояний
         */
        virtual void fillStateTable() override;

        /*!
         * \brief Основной метод построения таблицы разбора по заполненным перечням соcтояний (строки)
         * и символов грамматики (колонок)
         * \return true, если формирование завершилось успешно, иначе - false
         */
        virtual bool fillParseTable() override;

    protected:
        /*!
         * \brief Метод построения набора состояний для заданного номера состояния таблицы разбора
         * (используется рекурсивно)
         * \param state_no Номер состояния таблицы разбора
         */
        void fillStateInfo(size_t state_no);

        /*!
         * \brief Метод поиска заданной основной позиции в наборе состояний
         * \param rno Номер правила в перечне правил грамматики
         * \param pos Позиция состояния внутри правила
         * \return    Номер состояния, если оно найдено или 0, если не найдено (нулевое состояние является
         * исскуственным и ни когда не может быть найдено)
         */
        uint16_t findMainPosition(size_t rno, size_t pos) const;

        /*!
         * \brief Метод заполнения всех наведённых позиций при раскрутке символа грамматики,
         * стоящего после позиции (используется рекурсивно)
         * \param state_no  Номер состояний
         * \param lex       Символ грамматики
         */
        void    fillPreClosure(size_t state_no, const inout::Lexeme &lex) const;

        /*!
         * \brief Заполнение конкретной ячейки в таблице разбора
         * \param line      Номер состояние (строка таблицы)
         * \param column    Номер символа грамматики (колонка таблицы)
         * \param value     Значение
         * \return true, если заполнение завершилось успешно, иначе - false
         */
        bool    insertValue(size_t line, size_t column, parser::Fsm_value_t value);

        /*!
         * \brief Формирование перечня символов грамматики, которые должны быть обработаны для свёртки указанного правила
         *
         * Метод используется для вормирования списка колонок очередного состояния, по которым нужно выполнить свёртку
         * (используется рекурсивно вверх по продукциям нетерминальных символов).
         *
         * \param reduce_symbols Формируемый перечень символов грамматики, которые необходимо обрабатывать
         * \param rule_set  Набор комбинаций правил и позиций, которые уже обработаны (используется для оптимизации)
         * \param rule_no   Номер правила грамматики, для которого нужно выполнить наполнение
         */
        void    fillReduceSymbolsUp(std::vector<inout::Lexeme> & reduce_symbols, std::set<size_t> & rule_set, size_t rule_no);

        /*!
         * \brief Формирование перечня символов грамматики, которые должны быть обработаны для указанного символа грамматики
         *
         * Метод используется для вормирования списка колонок очередного состояния, по которым нужно выполнить свёртку
         * (используется рекурсивно вниз до достижения терминальных символов).
         *
         * \param reduce_symbols Формируемый перечень символов грамматики, которые необходимо обрабатывать
         * \param production     Символ грамматики для которого нужно выполнить поиск производных вниз до терминала
         * \param processed      Множество обработанных нетерминалов для предотвращения зацикливания
         */
        void    fillReduceSymbolsDown(std::vector<inout::Lexeme> & reduce_symbols, const std::u16string & production, std::set<inout::Lexeme> & processed);
    };
}

#endif // simodo_interpret_host_fuze_ParsingTableBuilder_SLR
